package com.sneakxy.cloudbase.platform.controller;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authz.annotation.Logical;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Sort;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.sneakxy.cloudbase.platform.bean.Dict;
import com.sneakxy.cloudbase.platform.bean.ValidAdd;
import com.sneakxy.cloudbase.platform.bean.ValidEdit;
import com.sneakxy.cloudbase.platform.bean.dto.DictDTO;
import com.sneakxy.cloudbase.platform.service.IDictService;
import com.sneakxy.cloudbase.platform.utils.web.BeanHelper;
import com.sneakxy.cloudbase.platform.utils.web.DataGrid;
import com.sneakxy.cloudbase.platform.utils.web.PageSearch;
import com.sneakxy.cloudbase.platform.utils.web.Response;
import com.sneakxy.cloudbase.platform.utils.web.signature.RequireSignature;
import com.sneakxy.mybatis.commons.repository.query.domain.CriteriaBuilder;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import springfox.documentation.annotations.ApiIgnore;

@Api(tags="数据字典服务接口")
@RestController
@RequestMapping("/api/dict/")
public class DictController {

	@Autowired
	private IDictService dictService;
	
	@ApiOperation("查询字典分页列表数据")
	@RequireSignature
	@RequiresPermissions("sys:dict:manager")
	@PostMapping("datagrid")
	public Response<DataGrid<DictDTO>> datagrid(PageSearch<String> search) {
		if(StringUtils.isBlank(search.getSortName())) {
			search.setSortName("sort");
		}
		final CriteriaBuilder<Dict> builder = new CriteriaBuilder<>(Dict.class);
		if(StringUtils.isNotBlank(search.getSearch())) {
			String value = StringUtils.join("%", StringUtils.trimToEmpty(search.getSearch()), "%");
			builder.andLike("label", value, "(", "");
			builder.orLike("memo", value);
			builder.orLike(DictDTO.FIELD_NAME_VALUE, value, "", ")");
		}
		builder.andIsNull(DictDTO.FIELD_NAME_PARENT_ID);
		Page<Dict> page = dictService.findAll(builder.build(), search.toPageable());
		return Response.ok(DataGrid.newInstance(page, DictDTO::from));
	}
	
	@ApiOperation("查询字典值分页列表数据")
	@RequireSignature
	@RequiresPermissions("sys:dict:manager:value")
	@PostMapping("value/datagrid")
	public Response<DataGrid<DictDTO>> datagrid(
			PageSearch<String> search,
			@ApiParam(name="parent_id", value="所属数据字典ID", required=true)
			@RequestParam(name="parent_id")
			String parentId) {
		if(StringUtils.isBlank(search.getSortName())) {
			search.setSortName("sort");
		}
		final CriteriaBuilder<Dict> builder = new CriteriaBuilder<>(Dict.class);
		if(StringUtils.isNotBlank(search.getSearch())) {
			String value = StringUtils.join("%", StringUtils.trimToEmpty(search.getSearch()), "%");
			builder.andLike("label", value, "(", "");
			builder.orLike("memo", value);
			builder.orLike(DictDTO.FIELD_NAME_VALUE, value, "", ")");
		}
		builder.andEq(DictDTO.FIELD_NAME_PARENT_ID, parentId);
		Page<Dict> page = dictService.findAll(builder.build(), search.toPageable());
		return Response.ok(DataGrid.newInstance(page, DictDTO::from));
	}
	
	@ApiImplicitParams({
		@ApiImplicitParam(name="label", value="数据字典标签", dataType="String", dataTypeClass = String.class, paramType="query", required=true),
		@ApiImplicitParam(name="memo", value="数据字典备注", dataType="String", dataTypeClass = String.class, paramType="query", required=false),
		@ApiImplicitParam(name="parentId", value="上级数据字典ID", dataType="String", dataTypeClass = String.class, paramType="query", required=false),
		@ApiImplicitParam(name="sort", value="数据字典排序", dataType="int", dataTypeClass = Integer.class, paramType="query", required=true),
		@ApiImplicitParam(name="value", value="数据字典值", dataType="String", dataTypeClass = String.class, paramType="query", required=true)
	})
	@ApiOperation("添加字典信息")
	@RequireSignature
	@RequiresPermissions("sys:dict:manager:add")
	@PostMapping("add")
	public Response<DictDTO> add(
			@Validated(ValidAdd.class) 
			@ApiIgnore 
			DictDTO dto) {
		if(!validate(dto.getValue()).getData()) {
			return Response.fail(1);
		}
		//去空格
		BeanHelper.trimToEmpty(dto);
		
		Dict dict = DictDTO.to(dto);
		dict.setParentId(null);
		dict.setDictId(null);
		dict.setId(null);
		dict.setLevel(0);
		dictService.save(dict);
		
		return Response.ok(DictDTO.from(dict));
	}
	
	@ApiImplicitParams({
		@ApiImplicitParam(name="id", value="数据字典ID", dataType="String", dataTypeClass = String.class, paramType="query", required=true),
		@ApiImplicitParam(name="label", value="数据字典标签", dataType="String", dataTypeClass = String.class, paramType="query", required=true),
		@ApiImplicitParam(name="memo", value="数据字典备注", dataType="String", dataTypeClass = String.class, paramType="query", required=false),
		@ApiImplicitParam(name="parentId", value="上级数据字典ID", dataType="String", dataTypeClass = String.class, paramType="query", required=false),
		@ApiImplicitParam(name="sort", value="数据字典排序", dataType="int", dataTypeClass = Integer.class, paramType="query", required=true),
		@ApiImplicitParam(name="value", value="数据字典值", dataType="String", dataTypeClass = String.class, paramType="query", required=true)
	})
	@ApiOperation("字典信息修改")
	@RequireSignature
	@RequiresPermissions("sys:dict:manager:edit")
	@PostMapping("edit")
	public Response<DictDTO> edit(
			@Validated(ValidEdit.class) 
			@ApiIgnore 
			DictDTO dto) {
		if(!validateEdit(dto.getId(), dto.getValue()).getData()) {
			return Response.fail(1);
		}
		//去空格
		BeanHelper.trimToEmpty(dto);
		
		Dict dict = DictDTO.to(dto);
		dict.setParentId(null);
		dict.setDictId(null);
		dict.setLevel(null);
		Dict result = dictService.save(dict);
		
		return Response.ok(DictDTO.from(result));
	}
	
	@ApiImplicitParams({
		@ApiImplicitParam(name="label", value="数据字典标签", dataType="String", dataTypeClass = String.class, paramType="query", required=true),
		@ApiImplicitParam(name="memo", value="数据字典备注", dataType="String", dataTypeClass = String.class, paramType="query", required=false),
		@ApiImplicitParam(name="parentId", value="上级数据字典ID", dataType="String", dataTypeClass = String.class, paramType="query", required=true),
		@ApiImplicitParam(name="sort", value="数据字典排序", dataType="int", dataTypeClass = Integer.class, paramType="query", required=true),
		@ApiImplicitParam(name="value", value="数据字典值", dataType="String", dataTypeClass = String.class, paramType="query", required=true)
	})
	@ApiOperation("添加字典值")
	@RequireSignature
	@RequiresPermissions("sys:dict:manager:value:add")
	@PostMapping("value/add")
	public Response<DictDTO> valueAdd(
			@Validated(ValidAdd.class)
			@ApiIgnore 
			DictDTO dto) {
		if(!validate(dto.getParentId(), dto.getValue()).getData()) {
			return Response.fail(1);
		}
		Dict parent = dictService.findOne(dto.getParentId());
		//去空格
		BeanHelper.trimToEmpty(dto);
		
		Dict dict = DictDTO.to(dto);
		dict.setId(null);
		dict.setDictId(parent.getLevel() > 0 ? parent.getDictId() : parent.getId());
		dict.setLevel(parent.getLevel() + 1);
		Dict result = dictService.save(dict);
		
		return Response.ok(DictDTO.from(result));
	}
	
	@ApiImplicitParams({
		@ApiImplicitParam(name="id", value="数据字典ID", dataType="String", dataTypeClass = String.class, paramType="query", required=true),
		@ApiImplicitParam(name="label", value="数据字典标签", dataType="String", dataTypeClass = String.class, paramType="query", required=true),
		@ApiImplicitParam(name="memo", value="数据字典备注", dataType="String", dataTypeClass = String.class, paramType="query", required=false),
		@ApiImplicitParam(name="sort", value="数据字典排序", dataType="int", dataTypeClass = Integer.class, paramType="query", required=true),
		@ApiImplicitParam(name="value", value="数据字典值", dataType="String", dataTypeClass = String.class, paramType="query", required=true)
	})
	@ApiOperation("字典值修改")
	@RequireSignature
	@RequiresPermissions("sys:dict:manager:value:edit")
	@PostMapping("value/edit")
	public Response<DictDTO> valueEdit(
			@Validated(ValidEdit.class)
			@ApiIgnore 
			DictDTO dto) {
		Dict old = dictService.findOne(dto.getId());
		if(!this.validateEdit(dto.getId(), old.getParentId(), dto.getValue()).getData()) {
			return Response.fail(1);
		}
		//去空格
		BeanHelper.trimToEmpty(dto);
		
		Dict dict = DictDTO.to(dto);
		//不更新
		dict.setParentId(null);
		dict.setDictId(null);
		dict.setLevel(null);
		Dict result = dictService.save(dict);
		
		return Response.ok(DictDTO.from(result));
	}
	
	@ApiOperation("字典添加校验")
	@RequireSignature
	@RequiresPermissions("sys:dict:manager:add")
	@PostMapping("validate")
	public Response<Boolean> validate(
			@ApiParam(name="value", value="数据字典VALUE", required=true)
			@RequestParam(name="value")
			String value) {
		DictDTO dict = dictService.findByType(null, value, false);
		return Response.ok(dict == null);
	}
	
	@ApiOperation("字典值添加校验")
	@RequireSignature
	@RequiresPermissions("sys:dict:manager:value:add")
	@PostMapping("value/validate")
	public Response<Boolean> validate(
			@ApiParam(name="parent_id", value="所属数据字典ID", required=true)
			@RequestParam(name="parent_id")
			String parentId,
			@ApiParam(name="value", value="数据字典值VALUE", required=true)
			@RequestParam(name="value")
			String value) {
		DictDTO dict = dictService.findByType(parentId, value, false);
		return Response.ok(dict == null);
	}
	
	@ApiOperation("字典修改校验")
	@RequireSignature
	@RequiresPermissions("sys:dict:manager:edit")
	@PostMapping("validateEdit")
	public Response<Boolean> validateEdit(
			@ApiParam(name="id", value="数据字典值ID", required=true)
			@RequestParam(name="id")
			String id,
			@ApiParam(name="value", value="数据字典值VALUE", required=true)
			@RequestParam(name="value")
			String value) {
		return validateEdit(id, null, value);
	}
	
	@ApiOperation("字典值修改校验")
	@RequireSignature
	@RequiresPermissions("sys:dict:manager:value:edit")
	@PostMapping("value/validateEdit")
	public Response<Boolean> validateEdit(
			@ApiParam(name="id", value="数据字典值ID", required=true)
			@RequestParam(name="id")
			String id,
			@ApiParam(name="parent_id", value="所属数据字典ID")
			@RequestParam(name="parent_id", required = false)
			String parentId, 
			@ApiParam(name="value", value="数据字典值VALUE", required=true)
			@RequestParam(name="value")
			String value) {
		CriteriaBuilder<Dict> builder = new CriteriaBuilder<>(Dict.class);
		builder.andNotEq("id", id);
		builder.andEq(DictDTO.FIELD_NAME_VALUE, value);
		if(StringUtils.isBlank(parentId)) {
			builder.andIsNull(DictDTO.FIELD_NAME_PARENT_ID);
		} else {
			builder.andEq(DictDTO.FIELD_NAME_PARENT_ID, parentId);
		}
		boolean result = this.dictService.count(builder.build()) == 0; 
		return Response.ok(result);
	}
	
	@ApiOperation("字典删除")
	@RequireSignature
	@RequiresPermissions(
		value = {"sys:dict:manager:remove", "sys:dict:manager:value:remove"}, 
		logical = Logical.OR
	)
	@PostMapping("remove")
	public Response<List<Integer>> remove(
			@ApiParam(name="ids", value="数据字典ID集合", required=true)
			@RequestParam(name="ids")
			String[] ids) {
		int success = 0;
		int all = 0;
		List<Integer> result = new ArrayList<>();
		if(ids != null) {
			all = ids.length;
			for(String id: ids) {
				if(dictService.remove(id)) {
					success ++;
				}
			}
		}
		result.add(all);
		result.add(success);
		result.add(all - success);
		return Response.ok(result);
	}
	
	@ApiOperation("查询数据字典值")
	@RequireSignature
	@PostMapping("values")
	public Response<DictDTO> values(
			@ApiParam(name="values", value="数据字value集合", required=true)
			@RequestParam(name="values", required = true)
			String[] values, 
			@ApiParam(name="children", value="是否包含下级字典", required=true)
			@RequestParam(name="children", required = true)
			boolean children) {
		DictDTO result = dictService.findByValues(values, children);
		return Response.ok(result);
	}
	
	
	@ApiOperation("查找单个数据字典")
	@RequireSignature
	@PostMapping("one")
	public Response<DictDTO> one(
			@ApiParam(name="id", value="数据字典ID", required=true)
			@RequestParam(name="id", required = true)
			String id) {
		Dict dict = dictService.findOne(id);
		return Response.ok(dict, DictDTO::from);
	}
	
	@ApiOperation("根据类型查找单个数据字典")
	@RequireSignature
	@PostMapping("oneByType")
	public Response<DictDTO> oneByType(
			@ApiParam(name="parent_id", value="所属数据字典ID", required=false)
			@RequestParam(name="parent_id", required = false)
			String parentId,
			@ApiParam(name="value", value="数据字典VALUE", required=true)
			@RequestParam(name="value", required = true)
			String value, 
			@ApiParam(name="children", value="是否查询下级字典信息", required = false)
			@RequestParam(name="children", defaultValue="false", required = false)
			boolean children) {
		DictDTO result = dictService.findByType(parentId, value, children);
		return Response.ok(result);
	}
	
	@ApiOperation("数据字典关键值查询层级数据列表")
	@RequireSignature
	@PostMapping("dicts")
	public Response<Collection<DictDTO>> dicts(
			@ApiParam(name="key", value="数据字典关键值", required=true)
			@RequestParam(name="key", required = true)
			String key,
			@ApiParam(name="level", value="数据字典层级", required=true)
			@RequestParam(name="level", required = true)
			Integer level) {
		DictDTO dict = dictService.findByType(null, key, false);
		if(dict != null) {
			CriteriaBuilder<Dict> builder = new CriteriaBuilder<>(Dict.class);
			builder.andEq("dictId", dict.getId());
			builder.andEq("level", level);
			List<Dict> result = dictService.findAll(builder.build(), Sort.by("parent_id", "sort"));
			return Response.ok(DictDTO.from(result));
		}
		return Response.ok(new ArrayList<>());
	}
	
	@ApiOperation("数据字典关键值查询层级单个数据")
	@RequireSignature
	@PostMapping("dict")
	public Response<DictDTO> dict(
			@ApiParam(name="key", value="数据字典关键值", required=true)
			@RequestParam(name="key", required = true)
			String key,
			@ApiParam(name="level", value="数据字典层级", required=true)
			@RequestParam(name="level", required = true)
			Integer level,
			@ApiParam(name="value", value="数据字典值", required=true)
			@RequestParam(name="value", required = true)
			String value) {
		DictDTO dict = dictService.findByType(null, key, false);
		if(dict != null) {
			CriteriaBuilder<Dict> builder = new CriteriaBuilder<>(Dict.class);
			builder.andEq("dictId", dict.getId());
			builder.andEq("level", level);
			builder.andEq(DictDTO.FIELD_NAME_VALUE, value);
			Dict result = dictService.findOne(builder.build());
			return Response.ok(result, DictDTO::from);
		}
		return Response.ok();
	}
	
}
